package com.gitee.ixtf.vertx.verticle

import io.smallrye.config.ConfigMapping
import io.vertx.core.DeploymentOptions
import io.vertx.core.ThreadingModel
import io.vertx.core.Vertx
import io.vertx.core.VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE
import io.vertx.core.json.JsonObject
import io.vertx.kotlin.core.deploymentOptionsOf
import io.vertx.kotlin.coroutines.coAwait
import java.util.*
import org.eclipse.microprofile.config.inject.ConfigProperty

open class BaseMainVerticle : BaseCoroutineVerticle() {
  @ConfigProperty protected lateinit var deploy: VertxDeploy

  override suspend fun start() {
    deploy.verticles().forEach { config ->
      val options = VertxDeployVerticleOptions.deploymentOptions(config)
      vertx.deployVerticle(config.name(), options).coAwait()
      println("deployVerticle[" + options.instances + "]: " + config.name())
    }
  }
}

@ConfigMapping(prefix = "deploy")
interface VertxDeploy {
  fun verticles(): List<VertxDeployVerticle>
}

/** [Vertx.deployVerticle] */
interface VertxDeployVerticle {
  fun name(): String

  /** [DeploymentOptions] */
  fun options(): Optional<VertxDeployVerticleOptions>
}

interface VertxDeployVerticleOptions {
  companion object {
    fun deploymentOptions(config: VertxDeployVerticle): DeploymentOptions =
        config.options().map { deploymentOptions(it) }.orElseGet { defaultDeploymentOptions() }

    private fun defaultDeploymentOptions() =
        deploymentOptionsOf(instances = DEFAULT_EVENT_LOOP_POOL_SIZE)

    private fun deploymentOptions(ops: VertxDeployVerticleOptions) =
        defaultDeploymentOptions().apply {
          config = JsonObject(ops.config())
          ops.instances().ifPresent { instances = it }
          ops.worker().ifPresent { threadingModel = ThreadingModel.WORKER }
        }
  }

  fun config(): Map<String, String>

  fun instances(): OptionalInt

  fun worker(): Optional<Boolean>
}
